﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.CApMovMovieManagerDxPlay
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using DirectShowLib;
using Microsoft.Win32.SafeHandles;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;


namespace DnProcessSimulateCommands;

internal class CApMovMovieManagerDxPlay : IDisposable
{
  private string m_sFileName;
  private IFilterGraph2 m_FilterGraph;
  private IMediaControl m_mediaCtrl;
  private IMediaEvent m_mediaEvent;
  private ISampleGrabber m_sampGrabber;
  private int m_videoWidth;
  private int m_videoHeight;
  private int m_stride;
  private int m_ImageSize;
  private Control _hWin;
  private int defHeight = 270;
  private int defWidth = 396;
  private ManualResetEvent m_mre;
  private volatile CApMovMovieManagerDxPlay.GraphState m_State;

  public void Dispose() => this.CloseInterfaces();

  ~CApMovMovieManagerDxPlay() => this.CloseInterfaces();

  public event CApMovMovieManagerDxPlay.DxPlayEvent StopPlay;

  public CApMovMovieManagerDxPlay(Control hWin, string FileName)
  {
    try
    {
      this._hWin = hWin;
      this.m_sFileName = FileName;
      this.SetupGraph(hWin, FileName);
      IntPtr existingHandle;
      DsError.ThrowExceptionForHR(this.m_mediaEvent.GetEventHandle(ref existingHandle));
      this.m_mre = new ManualResetEvent(false);
      this.m_mre.SafeWaitHandle = new SafeWaitHandle(existingHandle, true);
      new Thread(new ThreadStart(this.EventWait))
      {
        Name = "Media Event Thread"
      }.Start();
    }
    catch
    {
      this.Dispose();
      throw;
    }
  }

  private void EventWait()
  {
    while (!this.m_mre.SafeWaitHandle.IsClosed)
    {
      this.m_mre.WaitOne(-1, true);
      lock (this)
      {
        if (this.m_State == CApMovMovieManagerDxPlay.GraphState.Exiting)
          break;
        EventCode eventCode;
        IntPtr num1;
        IntPtr num2;
        int num3;
        for (num3 = this.m_mediaEvent.GetEvent(ref eventCode, ref num1, ref num2, 0); num3 >= 0; num3 = this.m_mediaEvent.GetEvent(ref eventCode, ref num1, ref num2, 0))
        {
          if (eventCode == 1)
          {
            this.Stop();
            if (this.StopPlay != null)
              this.StopPlay((object) this, new EventArgs());
          }
          DsError.ThrowExceptionForHR(this.m_mediaEvent.FreeEventParams(eventCode, num1, num2));
        }
        if (num3 != -2147467260 /*0x80004004*/)
          DsError.ThrowExceptionForHR(num3);
      }
    }
  }

  public string FileName => this.m_sFileName;

  public void Start()
  {
    if (this.m_State != CApMovMovieManagerDxPlay.GraphState.Stopped && this.m_State != CApMovMovieManagerDxPlay.GraphState.Paused)
      return;
    DsError.ThrowExceptionForHR(this.m_mediaCtrl.Run());
    this.m_State = CApMovMovieManagerDxPlay.GraphState.Running;
  }

  public bool Playing => this.m_State == CApMovMovieManagerDxPlay.GraphState.Running;

  public double Position
  {
    get
    {
      double position;
      int num = (this.m_FilterGraph as IMediaPosition)[ref position];
      return position;
    }
    set
    {
      (this.m_FilterGraph as IMediaPosition).put_CurrentPosition(value);
      this.Start();
      this.Pause();
    }
  }

  public double Duration
  {
    get
    {
      double duration;
      int num = (this.m_FilterGraph as IMediaPosition)[ref duration];
      return duration;
    }
  }

  public void Pause()
  {
    if (this.m_State != CApMovMovieManagerDxPlay.GraphState.Running)
      return;
    DsError.ThrowExceptionForHR(this.m_mediaCtrl.Pause());
    this.m_State = CApMovMovieManagerDxPlay.GraphState.Paused;
  }

  public void Stop()
  {
    if (this.m_State != CApMovMovieManagerDxPlay.GraphState.Running && this.m_State != CApMovMovieManagerDxPlay.GraphState.Paused)
      return;
    DsError.ThrowExceptionForHR(this.m_mediaCtrl.Stop());
    this.m_State = CApMovMovieManagerDxPlay.GraphState.Stopped;
    this.Rewind();
  }

  public void Rewind()
  {
    (this.m_FilterGraph as IMediaPosition).put_CurrentPosition(0.0);
    this.Start();
    this.Pause();
  }

  public IntPtr SnapShot()
  {
    IntPtr zero = IntPtr.Zero;
    int cb = 0;
    DsError.ThrowExceptionForHR(this.m_sampGrabber.GetCurrentBuffer(ref cb, zero));
    IntPtr num = Marshal.AllocCoTaskMem(cb);
    DsError.ThrowExceptionForHR(this.m_sampGrabber.GetCurrentBuffer(ref cb, num));
    return num;
  }

  public Bitmap IPToBmp(IntPtr ip)
  {
    int num = this.m_videoWidth * this.m_videoHeight * 3;
    return new Bitmap(this.m_videoWidth, this.m_videoHeight, -this.m_stride, PixelFormat.Format24bppRgb, (IntPtr) (ip.ToInt32() + num - this.m_stride));
  }

  private void SetupGraph(Control hWin, string FileName)
  {
    this.m_FilterGraph = new FilterGraph() as IFilterGraph2;
    ICaptureGraphBuilder2 o = new CaptureGraphBuilder2() as ICaptureGraphBuilder2;
    try
    {
      DsError.ThrowExceptionForHR(o.SetFiltergraph((IGraphBuilder) this.m_FilterGraph));
      IBaseFilter ibaseFilter = (IBaseFilter) null;
      DsError.ThrowExceptionForHR(this.m_FilterGraph.AddSourceFilter(FileName, FileName, ref ibaseFilter));
      this.m_sampGrabber = (ISampleGrabber) new SampleGrabber();
      IBaseFilter sampGrabber = (IBaseFilter) this.m_sampGrabber;
      this.ConfigureSampleGrabber(this.m_sampGrabber);
      DsError.ThrowExceptionForHR(this.m_FilterGraph.AddFilter(sampGrabber, "Ds.NET Grabber"));
      DsError.ThrowExceptionForHR(o.RenderStream((DsGuid) null, (DsGuid) null, (object) ibaseFilter, sampGrabber, (IBaseFilter) null));
      this.SaveSizeInfo(this.m_sampGrabber);
      this.ConfigureVideoWindow(this.m_FilterGraph as IVideoWindow, hWin);
      this.m_mediaEvent = this.m_FilterGraph as IMediaEvent;
      this.m_mediaCtrl = this.m_FilterGraph as IMediaControl;
    }
    finally
    {
      if (o != null)
        Marshal.ReleaseComObject((object) o);
    }
  }

  private void ConfigureVideoWindow(IVideoWindow videoWindow, Control hWin)
  {
    DsError.ThrowExceptionForHR(videoWindow.put_Owner(hWin.Handle));
    DsError.ThrowExceptionForHR(videoWindow.put_WindowStyle((WindowStyle) 1174405120 /*0x46000000*/));
    DsError.ThrowExceptionForHR(videoWindow.put_Visible((OABool) -1));
    this.ResizeVideoWindow();
  }

  public void ResizeVideoWindow()
  {
    Rectangle clientRectangle = this._hWin.ClientRectangle;
    IVideoWindow filterGraph = this.m_FilterGraph as IVideoWindow;
    double num1 = (double) this.defWidth / (double) this.defHeight;
    double num2 = (double) clientRectangle.Width / (double) clientRectangle.Height;
    int num3 = 0;
    int num4 = 0;
    int num5 = clientRectangle.Height;
    int num6 = clientRectangle.Width;
    if (num2 < num1)
    {
      num5 = (int) ((double) (clientRectangle.Width * this.defHeight) / (double) this.defWidth);
      num4 = (int) ((double) (clientRectangle.Height - num5) / 2.0);
    }
    else if (num2 > num1)
    {
      num6 = (int) ((double) (this.defWidth * clientRectangle.Height) / (double) this.defHeight);
      num3 = (int) ((double) (clientRectangle.Width - num6) / 2.0);
    }
    DsError.ThrowExceptionForHR(filterGraph.SetWindowPosition(num3, num4, num6, num5));
  }

  private void ConfigureSampleGrabber(ISampleGrabber sampGrabber)
  {
    AMMediaType amMediaType = new AMMediaType();
    amMediaType.majorType = MediaType.Video;
    amMediaType.subType = MediaSubType.RGB24;
    amMediaType.formatType = FormatType.VideoInfo;
    DsError.ThrowExceptionForHR(sampGrabber.SetMediaType(amMediaType));
    DsUtils.FreeAMMediaType(amMediaType);
    DsError.ThrowExceptionForHR(sampGrabber.SetBufferSamples(true));
  }

  private void SaveSizeInfo(ISampleGrabber sampGrabber)
  {
    AMMediaType amMediaType = new AMMediaType();
    DsError.ThrowExceptionForHR(sampGrabber.GetConnectedMediaType(amMediaType));
    try
    {
      if (amMediaType.formatType != FormatType.VideoInfo || amMediaType.formatPtr == IntPtr.Zero)
        throw new NotSupportedException("Unknown Grabber Media Format");
      VideoInfoHeader structure = new VideoInfoHeader();
      Marshal.PtrToStructure<VideoInfoHeader>(amMediaType.formatPtr, structure);
      this.m_videoWidth = structure.BmiHeader.Width;
      this.m_videoHeight = structure.BmiHeader.Height;
      this.m_stride = structure.BmiHeader.ImageSize / this.m_videoHeight;
      this.m_ImageSize = structure.BmiHeader.ImageSize;
    }
    finally
    {
      DsUtils.FreeAMMediaType(amMediaType);
    }
  }

  private void CloseInterfaces()
  {
    lock (this)
    {
      if (this.m_State != CApMovMovieManagerDxPlay.GraphState.Exiting)
      {
        this.m_State = CApMovMovieManagerDxPlay.GraphState.Exiting;
        if (this.m_mre != null && !this.m_mre.SafeWaitHandle.IsInvalid)
        {
          this.m_mre.Set();
          this.m_mre.SafeWaitHandle.SetHandleAsInvalid();
        }
      }
      if (this.m_mediaCtrl != null)
      {
        this.m_mediaCtrl.Stop();
        this.m_mediaCtrl = (IMediaControl) null;
      }
      if (this.m_sampGrabber != null)
      {
        Marshal.ReleaseComObject((object) this.m_sampGrabber);
        this.m_sampGrabber = (ISampleGrabber) null;
      }
      if (this.m_FilterGraph != null)
      {
        Marshal.ReleaseComObject((object) this.m_FilterGraph);
        this.m_FilterGraph = (IFilterGraph2) null;
      }
    }
    GC.Collect();
  }

  private enum GraphState
  {
    Stopped,
    Paused,
    Running,
    Exiting,
  }

  public delegate void DxPlayEvent(object sender, EventArgs args);
}
